#![allow(unused)]
#![feature(error_generic_member_access)]
#![feature(provide_any)]
#![feature(option_get_or_insert_default)]
#![feature(drain_filter)]
#![feature(hash_drain_filter)]
extern crate anyhow;
extern crate build_time;
extern crate bytes;
extern crate futures_channel;
extern crate hex;
extern crate log;
extern crate openssl;
extern crate rand;
extern crate serde;
extern crate serde_json;
extern crate thiserror;
extern crate tokio;
extern crate tokio_stream;
extern crate tokio_util;
extern crate tracing;
extern crate tracing_subscriber;
extern crate version;
// extern crate ring;
extern crate tokio_tungstenite;
extern crate url;

#[macro_use]
extern crate lazy_static;

extern crate app_dirs2;
extern crate async_stream;
extern crate async_trait;
extern crate futures_core;
extern crate futures_io;
extern crate futures_ringbuf;
extern crate futures_util;
extern crate headers;
extern crate http;
extern crate hyper;
extern crate md5;
extern crate mime_guess;
extern crate optional_struct;
extern crate path_clean;
extern crate pin_project;
extern crate regex;
extern crate reqwest;
extern crate simple_signal;
extern crate state;
extern crate symlink;
extern crate tonic;
extern crate tonic_inf;
extern crate tower;
extern crate uinput_tokio;
extern crate urlencoding;
extern crate uuid;
extern crate warp;
extern crate webrtc_ice;
extern crate webrtc_util;

pub mod contract;
pub mod imp;
pub mod model;
pub mod utils;

pub mod coolink_easy_api;
pub mod coolink_uinput;

use crate::coolink_easy_api::{
    is_manually_exited, CoolinkSDKEasyApi, HttpdInitArgs, IByteBufListener, ICoolinkEasyApi,
    IMessageTunnelListener, ISensorTunnelListener, IUniqueMessageTunnelListener, LogIntArgs,
    OptionalHttpdInitArgs, OptionalLogIntArgs, OptionalServerQueryInitArgs, ServerQueryInitArgs,
    UniqueByteBufTunnel, UniqueSensorTunnel, UniqueTunnel,
};

use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;
use tokio::sync::mpsc::unbounded_channel;
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};

use crate::coolink_uinput::{
    loop_block_on_u_keyboard, loop_block_on_u_mouse, CoolinkKey, MouseEvent,
};
use tokio::runtime::Builder;
use uinput_tokio::event::keyboard;

// 可信文本通道回调
struct MessageTunnelCallback {
    keyboard_sender: UnboundedSender<keyboard::Key>,
    mouse_sender: UnboundedSender<MouseEvent>,
}

impl IUniqueMessageTunnelListener for MessageTunnelCallback {
    /// P2PRPC 服务准备完成，通常发送端可以从收到这个回调开始，调用connect去发起连接，成功率为100%
    /// 接收端可以不处理
    fn on_p2p_rpc_service_ready(&self, local_client_id: String) {
        log::info!(
            "msgtunnel on_p2p_rpc_service_ready,client_id = {:?}",
            local_client_id
        );
    }
    /// Httpd 服务准备完成
    fn on_http_service_ready(&self, host: String) {
        log::info!("msgtunnel on_http_service_ready,host = {:?}", host);
    }
}

impl IMessageTunnelListener for MessageTunnelCallback {
    /// 调用connectAsControlling，成功或者失败会有回调
    fn on_connect_failed(&self, tunnel: UniqueTunnel, is_controlling: bool, err_reason: String) {
        log::info!(
            "msgtunnel on_connect_failed,tunnel = {:?}, is_controlling = {:?},err_reason = {:?}",
            tunnel,
            is_controlling,
            err_reason
        );
    }

    /// 代表有一个连接已经建立成功，is_controlling代表是发起连接的一端或者是被连接的一端
    /// 此时全双工的消息发送通道还未建立好，需要等onReadyToSend
    fn on_connected(&self, tunnel: UniqueTunnel, is_controlling: bool) {
        log::info!(
            "msgtunnel on_connected,tunnel = {:?},is_controlling = {:?}",
            tunnel,
            is_controlling
        );
    }

    /// 代表了可以发送消息了,
    fn on_ready_to_send(&self, tunnel: UniqueTunnel, ready_to_send: bool) {
        log::info!(
            "msgtunnel on_ready_to_send,tunnel = {:?},ready_to_send = {:?}",
            tunnel,
            ready_to_send
        );
    }

    /// 因为网络原因导致连接不稳定，内部正在进行重连，重连好了会调用onReadyToSend。
    fn on_connect_unstable(&self, tunnel: UniqueTunnel, is_controlling: bool) {
        log::info!(
            "msgtunnel on_connect_unstable,tunnel = {:?},is_controlling = {:?}",
            tunnel,
            is_controlling
        );
    }

    /// 该状态代表即将发生端开的状态，该状态回调之后，接下去会回调onConnected或者onDisconnected（耗时长）。
    /// 建议收到该消息后，重新完成P2PRPC通道的重置，能够加快连接
    fn on_pre_disconnect(&self, tunnel: UniqueTunnel, is_controlling: bool) {
        log::info!(
            "msgtunnel on_pre_disconnect,tunnel = {:?},is_controlling = {:?}",
            tunnel,
            is_controlling
        );
    }

    /// 连接断开了
    fn on_disconnected(&self, tunnel: UniqueTunnel, is_controlling: bool, err_reason: String) {
        log::info!(
            "msgtunnel on_disconnected,tunnel = {:?},is_controlling = {:?},err_reason={:?}",
            tunnel,
            is_controlling,
            err_reason
        );
    }

    /// 收到了文本连接通道的消息
    fn on_received(
        &self,
        tunnel: UniqueTunnel,
        is_controlling: bool,
        message_id: String,
        event: String,
        message: String,
    ) {
        // this message is form p2p tunnel, important!
        log::info!("msgtunnel on_received,tunnel = {:?},is_controlling = {:?},message_id={:?},event={:?},message={:?}", tunnel,is_controlling,message_id,event,message);
        if "REMOTE".to_string().eq_ignore_ascii_case(&event) {
            // 此通道是遥控器通道，用户可以转化为遥控器事件
            log::warn!("remote control :{:?}", message);
        } else if "KEYPAD".to_string().eq_ignore_ascii_case(&event) {
            // 此通道是键盘通道，用户可以转化为遥控器事件
            log::warn!("remote keyboard :{:?}", message);
            if let Some(key) = CoolinkKey::from_str(&message) {
                self.keyboard_sender.send(key).unwrap();
            }
        }
    }
}
// 可信sensor通道回调
struct SensorTunnelCallback {
    keyboard_sender: UnboundedSender<keyboard::Key>,
    mouse_sender: UnboundedSender<MouseEvent>,
}

impl ISensorTunnelListener for SensorTunnelCallback {
    /// 调用openSensorAsControlling，成功或者失败会有回调
    fn on_open_failed(&self, tunnel: UniqueSensorTunnel, is_controlling: bool, err_reason: String) {
        log::info!(
            "sensortunnel on_open_failed,tunnel = {:?}, is_controlling = {:?},err_reason = {:?}",
            tunnel,
            is_controlling,
            err_reason
        );
    }

    /// 代表有一个连接已经建立成功，is_controlling代表是发起连接的一端或者是被连接的一端
    /// 此时全双工的消息发送通道还未建立好，需要等onReadyToSend
    fn on_opened(&self, tunnel: UniqueSensorTunnel, is_controlling: bool) {
        log::info!(
            "sensortunnel on_opened,tunnel = {:?},is_controlling = {:?}",
            tunnel,
            is_controlling
        );
    }

    /// 代表了可以发送消息了,
    fn on_ready_to_send(&self, tunnel: UniqueSensorTunnel, ready_to_send: bool) {
        log::info!(
            "sensortunnel on_ready_to_send,tunnel = {:?},ready_to_send = {:?}",
            tunnel,
            ready_to_send
        );
    }

    /// 因为网络原因导致连接不稳定，内部正在进行重连，重连好了会调用onReadyToSend。
    fn on_open_tunnel_unstable(&self, tunnel: UniqueSensorTunnel, is_controlling: bool) {
        log::info!(
            "sensortunnel on_open_tunnel_unstable,tunnel = {:?},is_controlling = {:?}",
            tunnel,
            is_controlling
        );
    }

    /// 该状态代表即将发生端开的状态，该状态回调之后，接下去会回调onConnected或者onDisconnected（耗时长）。
    /// 建议收到该消息后，重新完成P2PRPC通道的重置，能够加快连接
    fn on_pre_closed(&self, tunnel: UniqueSensorTunnel, is_controlling: bool) {
        log::info!(
            "sensortunnel on_pre_closed,tunnel = {:?},is_controlling = {:?}",
            tunnel,
            is_controlling
        );
    }

    /// 连接断开了
    fn on_closed(&self, tunnel: UniqueSensorTunnel, is_controlling: bool, err_reason: String) {
        log::info!(
            "sensortunnel on_closed,tunnel = {:?},is_controlling = {:?},err_reason = {:?}",
            tunnel,
            is_controlling,
            err_reason
        );
    }

    /// 收到了sensor通道的消息
    fn on_sensor_data_received(
        &self,
        tunnel: UniqueSensorTunnel,
        is_controlling: bool,
        sensor_msg_id: String,
        sensor_event: String,
        semsor_data: String,
    ) {
        log::info!("sensortunnel on_received,tunnel = {:?},is_controlling = {:?},sensor_msg_id={:?},sensor_event={:?},semsor_data={:?}", tunnel,is_controlling,sensor_msg_id,sensor_event,semsor_data);
        if "SENSOR_MOBILE"
            .to_string()
            .eq_ignore_ascii_case(&sensor_event)
        {
            // 此通道是sensor通道，用户可以转化为鼠标数据
            log::warn!("remote mobile sensor :{:?}", semsor_data);
        }
    }
}

// 可信数组通道回调
struct ByteBufTunnelCallback;
impl IByteBufListener for ByteBufTunnelCallback {
    /// 调用startByteBufChannel的时候，成功或者失败会有回调
    fn on_open_failed(
        &self,
        tunnel: UniqueByteBufTunnel,
        is_controlling: bool,
        err_reason: String,
    ) {
        log::info!(
            "bytebuftunnel on_open_failed,tunnel = {:?}, is_controlling = {:?},err_reason = {:?}",
            tunnel,
            is_controlling,
            err_reason
        );
    }
    /// 代表有一个连接已经建立成功，is_controlling代表是发起连接的一端或者是被连接的一端
    /// 此时全双工的消息发送通道还未建立好，需要等onReadyToSend
    fn on_opened(&self, tunnel: UniqueByteBufTunnel, is_controlling: bool) {
        log::info!(
            "bytebuftunnel on_opened,tunnel = {:?},is_controlling = {:?}",
            tunnel,
            is_controlling
        );
    }
    /// 代表了可以发送消息了,
    fn on_ready_to_send(&self, tunnel: UniqueByteBufTunnel, ready_to_send: bool) {
        log::info!(
            "bytebuftunnel on_ready_to_send,tunnel = {:?},ready_to_send = {:?}",
            tunnel,
            ready_to_send
        );
    }
    /// 因为网络原因导致连接不稳定，内部正在进行重连，重连好了会调用onReadyToSend。
    fn on_open_tunnel_unstable(&self, tunnel: UniqueByteBufTunnel, is_controlling: bool) {
        log::info!(
            "bytebuftunnel on_open_tunnel_unstable,tunnel = {:?},is_controlling = {:?}",
            tunnel,
            is_controlling
        );
    }
    /// 该状态代表即将发生端开的状态，该状态回调之后，接下去会回调onConnected或者onDisconnected（耗时长）。
    /// 建议收到该消息后，重新完成P2PRPC通道的重置，能够加快连接
    fn on_pre_closed(&self, tunnel: UniqueByteBufTunnel, is_controlling: bool) {
        log::info!(
            "bytebuftunnel on_pre_closed,tunnel = {:?},is_controlling = {:?}",
            tunnel,
            is_controlling
        );
    }
    /// 连接断开了
    fn on_closed(&self, tunnel: UniqueByteBufTunnel, is_controlling: bool, err_reason: String) {
        log::info!(
            "bytebuftunnel on_closed,tunnel = {:?},is_controlling = {:?},err_reason={:?}",
            tunnel,
            is_controlling,
            err_reason
        );
    }
    /// 收到了bytebufer通道的消息
    fn on_bytebuf_received(
        &self,
        tunnel: UniqueByteBufTunnel,
        is_controlling: bool,
        byte_id: String,
        video: Vec<u8>,
        audio: Vec<u8>,
    ) {
        log::info!("sensortunnel on_bytebuf_received,tunnel = {:?},is_controlling = {:?},byte_id={:?},video={:?},audio={:?}", tunnel,is_controlling,byte_id,video,audio);
    }
}

// 信号处理器
fn signal_handler(tx: Sender<()>) {
    // 监听信号SIGTERM和SIGINT
    simple_signal::set_handler(
        &[simple_signal::Signal::Term, simple_signal::Signal::Int],
        move |_| {
            // 向通道发送消息
            tx.send(()).unwrap();
        },
    );
}

fn main() {
    // 提前初始化日志库，避免uinput节点报错不打印
    let sdk_init_arg_opt = OptionalLogIntArgs::default();
    let init_log_arg = LogIntArgs {
        tag: sdk_init_arg_opt.tag.unwrap(),
        log_level: "DEBUG".to_string(),
    };
    CoolinkSDKEasyApi::pre_init_sdk_log(init_log_arg);

    let (keyboard_tx, mut keyboard_rx): (
        UnboundedSender<keyboard::Key>,
        UnboundedReceiver<keyboard::Key>,
    ) = unbounded_channel();

    std::thread::spawn(move || {
        if let Ok(rt) = Builder::new_multi_thread()
            .on_thread_start(|| {
                // call_attach_fn();
            })
            .on_thread_stop(|| {
                // call_detach_fn();
            })
            .enable_all()
            .build()
        {
            // block on tokio async loop. sync_connect must be called in a thread!
            let res = rt.block_on(loop_block_on_u_keyboard(keyboard_rx));
            log::info!("虚拟键盘节点销毁");
        } else {
            log::info!("虚拟键盘节点创建失败");
        }
    });

    let (mouse_tx, mut mouse_rx): (UnboundedSender<MouseEvent>, UnboundedReceiver<MouseEvent>) =
        unbounded_channel();

    std::thread::spawn(move || {
        if let Ok(rt) = Builder::new_multi_thread()
            .on_thread_start(|| {
                // call_attach_fn();
            })
            .on_thread_stop(|| {
                // call_detach_fn();
            })
            .enable_all()
            .build()
        {
            // block on tokio async loop. sync_connect must be called in a thread!
            let res = rt.block_on(loop_block_on_u_mouse(mouse_rx));
            log::info!("虚拟鼠标节点销毁");
        } else {
            log::info!("虚拟鼠标节点创建失败");
        }
    });

    let (tx, rx): (Sender<()>, Receiver<()>) = mpsc::channel();

    // 创建线程运行信号处理器
    std::thread::spawn(move || {
        do_task(keyboard_tx.clone(), mouse_tx.clone());
        signal_handler(tx);
    });

    // 等待接收到信号
    let _ = rx.recv();

    //程序退出前的清理工作
    CoolinkSDKEasyApi::shut_down();
    log::info!("main函数结束");
}

// 编写耗时任务的代码
fn do_task(
    keyboard_sender: UnboundedSender<keyboard::Key>,
    mouse_sender: UnboundedSender<MouseEvent>,
) {
    // 这里写你的代码
    // 1、初始化 简易API SDK
    let srv_query_arg_opt = OptionalServerQueryInitArgs::default();
    let httpd_init_arg_opt = OptionalHttpdInitArgs::default();

    // 2、如果没有前置调用pre_init_sdk_log，日志的打印和等级就以此处的为准
    let sdk_init_arg_opt = OptionalLogIntArgs::default();
    let init_log_arg = LogIntArgs {
        tag: sdk_init_arg_opt.tag.unwrap(),
        log_level: "DEBUG".to_string(),
    };

    let srv_query_arg = ServerQueryInitArgs {
        host: srv_query_arg_opt.host.unwrap(),
        sg_url_subgroup: srv_query_arg_opt.sg_url_subgroup.unwrap(),
        turn_url_subgroup: srv_query_arg_opt.turn_url_subgroup.unwrap(),
        app_key: srv_query_arg_opt.app_key.unwrap(),
        app_secret: srv_query_arg_opt.app_secret.unwrap(),
        pkg_name: srv_query_arg_opt.pkg_name.unwrap(),
        device_id: srv_query_arg_opt.device_id.unwrap(),
        user_id: "tvos.uid-coolink".to_owned(),
        conig_save_dir_path: srv_query_arg_opt.conig_save_dir_path.unwrap(),
        download_save_dir_path: srv_query_arg_opt.download_save_dir_path.unwrap(),
    };

    let httpd_init_arg = HttpdInitArgs {
        http_root_route_path: httpd_init_arg_opt.http_root_route_path.unwrap(),
        http_root_www_dir_path: httpd_init_arg_opt.http_root_www_dir_path.unwrap(),
        http_remote_route_path: httpd_init_arg_opt.http_remote_route_path.unwrap(),
        http_remote_file_map_route_path: httpd_init_arg_opt
            .http_remote_file_map_route_path
            .unwrap(),
        http_listen_host: httpd_init_arg_opt.http_listen_host.unwrap(),
        http_listen_port: httpd_init_arg_opt.http_listen_port.unwrap(),
    };

    // 2、设置SDK通用参数
    CoolinkSDKEasyApi::init_easy_sdk(init_log_arg, srv_query_arg, httpd_init_arg);

    // 3、设置三条传输通道监听回调，等待收集端连接（受控端不需要调用相关主动接口）
    CoolinkSDKEasyApi::set_message_type_tunnel_listener(Box::new(MessageTunnelCallback {
        keyboard_sender: keyboard_sender.clone(),
        mouse_sender: mouse_sender.clone(),
    }));
    CoolinkSDKEasyApi::set_sensor_type_tunnel_listener(Box::new(SensorTunnelCallback {
        keyboard_sender: keyboard_sender.clone(),
        mouse_sender: mouse_sender.clone(),
    }));
    CoolinkSDKEasyApi::set_bytebuf_type_tunnel_listener(Box::new(ByteBufTunnelCallback));
}
